"""
监控系统定时任务
实现告警数据聚合、自动同步等功能
"""
import logging
import threading
import time
from datetime import datetime, timedelta
from typing import Dict, Any, List
from django.utils import timezone
from django.db import transaction
from django.contrib.auth.models import User
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

from .models import ZabbixServer, MonitoringAlert, MonitoringHost
from .utils.zabbix_api import ZabbixAPIManager
from .utils.alert_processor import alert_processor

logger = logging.getLogger(__name__)


class AlertAggregationService:
    """告警数据聚合服务"""

    def __init__(self):
        self.running = False
        self.sync_interval = 60  # 同步间隔60秒
        self.thread = None
        self.channel_layer = get_channel_layer()

    def start(self):
        """启动告警聚合服务"""
        if not self.running:
            self.running = True
            self.thread = threading.Thread(target=self._sync_loop, daemon=True)
            self.thread.start()
            logger.info("告警聚合服务已启动")

    def stop(self):
        """停止告警聚合服务"""
        self.running = False
        if self.thread:
            self.thread.join()
        logger.info("告警聚合服务已停止")

    def _sync_loop(self):
        """同步循环"""
        escalation_counter = 0
        while self.running:
            try:
                # 同步告警
                self.sync_all_alerts()

                # 每5次同步执行一次告警升级检查（5分钟）
                escalation_counter += 1
                if escalation_counter >= 5:
                    try:
                        alert_processor.process_alert_escalation()
                        escalation_counter = 0
                    except Exception as e:
                        logger.error(f"告警升级处理失败: {e}")

            except Exception as e:
                logger.error(f"告警同步出错: {e}")

            # 等待下次同步
            time.sleep(self.sync_interval)

    def sync_all_alerts(self):
        """同步所有活跃Zabbix服务器的告警"""
        active_servers = ZabbixServer.objects.filter(is_active=True)

        for server in active_servers:
            try:
                result = self.sync_server_alerts(server)
                if result['success'] and result.get('new_alerts'):
                    # 发送实时通知
                    self._send_realtime_notifications(result['new_alerts'])

            except Exception as e:
                logger.error(f"同步服务器 {server.name} 告警失败: {e}")

    def sync_server_alerts(self, zabbix_server: ZabbixServer) -> Dict[str, Any]:
        """同步单个Zabbix服务器的告警"""
        try:
            api_manager = ZabbixAPIManager(zabbix_server)
            result = api_manager.get_alerts()

            if not result['success']:
                return {
                    'success': False,
                    'error': result.get('error', '获取告警失败')
                }

            alerts = result['data']
            new_alerts = []
            updated_alerts = []

            for alert_data in alerts:
                try:
                    alert_result = self._process_alert_data(alert_data, zabbix_server)
                    if alert_result['created']:
                        new_alerts.append(alert_result['alert'])
                    elif alert_result['updated']:
                        updated_alerts.append(alert_result['alert'])

                except Exception as e:
                    logger.warning(f"处理告警数据失败: {e}")
                    continue

            return {
                'success': True,
                'total_alerts': len(alerts),
                'new_alerts': new_alerts,
                'updated_alerts': updated_alerts,
                'new_count': len(new_alerts),
                'updated_count': len(updated_alerts)
            }

        except Exception as e:
            logger.error(f"同步服务器告警失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def _process_alert_data(self, alert_data: Dict, zabbix_server: ZabbixServer) -> Dict[str, Any]:
        """处理单个告警数据"""
        event_id = alert_data.get('eventid')
        if not event_id:
            raise ValueError("告警数据缺少事件ID")

        # 查找关联的主机
        host_name = None
        if alert_data.get('hosts') and len(alert_data['hosts']) > 0:
            host_name = alert_data['hosts'][0].get('host')

        monitoring_host = None
        if host_name:
            try:
                # 首先尝试精确匹配
                monitoring_host = MonitoringHost.objects.get(
                    zabbix_server=zabbix_server,
                    zabbix_host_name=host_name
                )
            except MonitoringHost.DoesNotExist:
                try:
                    # 如果精确匹配失败，尝试通过CMDB主机名匹配
                    monitoring_host = MonitoringHost.objects.get(
                        zabbix_server=zabbix_server,
                        host__hostname=host_name
                    )
                except MonitoringHost.DoesNotExist:
                    # 尝试模糊匹配（处理空格和连字符的差异）
                    normalized_host_name = host_name.replace(' ', '-').replace('_', '-').lower()
                    for mhost in MonitoringHost.objects.filter(zabbix_server=zabbix_server):
                        normalized_mhost_name = mhost.host.hostname.replace(' ', '-').replace('_', '-').lower()
                        if normalized_mhost_name == normalized_host_name:
                            monitoring_host = mhost
                            break

                    if not monitoring_host:
                        logger.warning(f"未找到监控主机: {host_name}")

        # 如果没有找到关联主机，记录警告但继续处理告警
        if not monitoring_host and host_name:
            logger.warning(f"告警 {event_id} 关联的主机 {host_name} 未在系统中找到，将创建无主机关联的告警记录")
        elif not host_name:
            logger.warning(f"告警 {event_id} 没有关联的主机信息，将创建无主机关联的告警记录")

        # 映射告警级别
        severity = self._map_zabbix_severity(alert_data.get('severity', '0'))

        # 确定告警状态
        status = 'resolved' if alert_data.get('r_eventid', '0') != '0' else 'active'

        # 解析事件时间
        event_time = timezone.now()
        if alert_data.get('clock'):
            try:
                event_time = datetime.fromtimestamp(int(alert_data['clock']), tz=timezone.get_current_timezone())
            except (ValueError, TypeError):
                pass

        # 检查是否存在已删除的告警
        existing_alert = MonitoringAlert.objects.filter(
            zabbix_server=zabbix_server,
            zabbix_event_id=event_id
        ).first()

        if existing_alert and existing_alert.status == 'deleted':
            logger.info(f"跳过已删除的告警: {existing_alert.title} (Event ID: {event_id})")
            return None

        # 创建或更新告警记录
        alert_obj, created = MonitoringAlert.objects.get_or_create(
            zabbix_server=zabbix_server,
            zabbix_event_id=event_id,
            defaults={
                'host': monitoring_host.host if monitoring_host else None,
                'title': alert_data.get('name', '未知告警'),
                'description': alert_data.get('name', ''),
                'severity': severity,
                'status': status,
                'event_time': event_time,
                'zabbix_trigger_id': alert_data.get('objectid', ''),
                'raw_data': alert_data
            }
        )

        updated = False
        if not created:
            # 更新现有告警的状态
            old_status = alert_obj.status
            if old_status != status:
                alert_obj.status = status
                if status == 'resolved':
                    alert_obj.resolved_time = timezone.now()
                alert_obj.save()
                updated = True
        else:
            # 新告警，应用告警处理规则
            try:
                process_result = alert_processor.process_new_alert(alert_obj)
                logger.info(f"告警处理结果: {process_result}")
            except Exception as e:
                logger.error(f"处理新告警失败: {e}")

        return {
            'alert': alert_obj,
            'created': created,
            'updated': updated
        }

    def _map_zabbix_severity(self, severity_str: str) -> str:
        """映射Zabbix告警级别到系统级别"""
        severity_map = {
            '0': 'not_classified',  # 未分类
            '1': 'information',     # 信息
            '2': 'warning',         # 警告
            '3': 'average',         # 一般严重
            '4': 'high',            # 严重
            '5': 'disaster',        # 灾难
        }
        return severity_map.get(str(severity_str), 'not_classified')

    def _send_realtime_notifications(self, new_alerts: List[MonitoringAlert]):
        """发送实时通知"""
        if not new_alerts:
            return

        # WebSocket实时推送
        for alert in new_alerts:
            try:
                self._send_websocket_notification(alert)
            except Exception as e:
                logger.error(f"发送WebSocket通知失败: {e}")

        # 新的SSE实时推送
        for alert in new_alerts:
            try:
                self._send_sse_notification(alert)
            except Exception as e:
                logger.error(f"发送SSE通知失败: {e}")



    def _send_websocket_notification(self, alert: MonitoringAlert):
        """发送WebSocket通知"""
        if not self.channel_layer:
            return

        notification_data = {
            'type': 'alert_notification',
            'data': {
                'id': alert.id,
                'title': alert.title,
                'hostname': alert.host.hostname if alert.host else "未知主机",
                'severity': alert.severity,
                'status': alert.status,
                'event_time': alert.event_time.isoformat(),
                'zabbix_server': alert.zabbix_server.name
            }
        }

        # 发送到监控更新组
        async_to_sync(self.channel_layer.group_send)(
            'monitoring_updates',
            notification_data
        )

    def _send_sse_notification(self, alert: MonitoringAlert):
        """发送SSE通知"""
        try:
            from .sse_manager import sse_manager

            alert_data = {
                'id': alert.id,
                'title': alert.title,
                'hostname': alert.host.hostname if alert.host else "未知主机",
                'severity': alert.severity,
                'status': alert.status,
                'event_time': alert.event_time.isoformat(),
                'zabbix_server': alert.zabbix_server.name,
                'description': alert.description or '',
                'host_ip': alert.host.public_ip or alert.host.private_ip or alert.host.ip if alert.host else ''
            }

            # 广播到所有SSE连接
            sse_manager.broadcast_to_all('new_alert', alert_data)
            logger.info(f"SSE推送新告警: {alert.title}")

        except Exception as e:
            logger.error(f"发送SSE通知失败: {e}")




# 全局告警聚合服务实例 - 暂时禁用自动启动
alert_aggregation_service = AlertAggregationService()

# 立即停止服务，避免自动生成测试告警
try:
    alert_aggregation_service.stop()
    print("⚠️ 告警聚合服务已强制停止")
except Exception as e:
    print(f"停止告警聚合服务时出错: {e}")


def start_alert_aggregation():
    """启动告警聚合服务"""
    alert_aggregation_service.start()


def stop_alert_aggregation():
    """停止告警聚合服务"""
    alert_aggregation_service.stop()


class ZabbixAlertMonitor:
    """Zabbix告警监控器 - 实时获取和推送告警"""

    def __init__(self):
        self.is_running = False
        self.last_check_time = None
        self.known_alerts = set()  # 已知告警ID集合

    def start_monitoring(self):
        """启动告警监控"""
        if self.is_running:
            return

        self.is_running = True
        logger.info("🚀 Zabbix告警监控器已启动")

        # 启动监控线程
        import threading
        monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
        monitor_thread.start()

    def stop_monitoring(self):
        """停止告警监控"""
        self.is_running = False
        logger.info("⏹️ Zabbix告警监控器已停止")

    def _monitor_loop(self):
        """监控循环"""
        while self.is_running:
            try:
                self._check_new_alerts()
                time.sleep(30)  # 每30秒检查一次
            except Exception as e:
                logger.error(f"告警监控循环出错: {e}")
                time.sleep(60)  # 出错后等待1分钟再重试

    def _check_new_alerts(self):
        """检查新告警并同步到数据库"""
        try:
            from .models import ZabbixServer, MonitoringAlert, MonitoringHost
            from .utils.zabbix_api import ZabbixAPIManager
            from .sse_manager import sse_manager

            # 获取活跃的Zabbix服务器
            active_servers = ZabbixServer.objects.filter(
                is_active=True,
                connection_status='connected'
            )

            for server in active_servers:
                try:
                    api_manager = ZabbixAPIManager(server)
                    result = api_manager.get_alerts()

                    if result['success']:
                        alerts = result['data']
                        new_alerts = []
                        synced_alerts = []

                        for alert in alerts:
                            alert_id = f"{server.id}_{alert.get('eventid', alert.get('problemid'))}"

                            # 检查是否是新告警（用于SSE推送）
                            is_new_alert = alert_id not in self.known_alerts
                            if is_new_alert:
                                self.known_alerts.add(alert_id)
                                new_alerts.append(alert)

                            # 同步告警到数据库（无论是否新告警）
                            try:
                                # 获取主机信息
                                hostname = "未知主机"
                                host_instance = None
                                if alert.get('hosts') and len(alert['hosts']) > 0:
                                    zabbix_host = alert['hosts'][0]
                                    hostname = zabbix_host.get('name', zabbix_host.get('host', '未知主机'))

                                    # 尝试多种方式找到对应的Host实例
                                    try:
                                        from cmdb.models import Host
                                        from django.db import models

                                        # 方式1：通过hostname精确匹配
                                        host_instance = Host.objects.filter(hostname=hostname).first()

                                        # 方式2：如果没找到，尝试通过IP地址匹配
                                        if not host_instance:
                                            # 从MonitoringHost中获取IP信息
                                            try:
                                                monitoring_host = MonitoringHost.objects.filter(
                                                    zabbix_host_id=zabbix_host.get('hostid'),
                                                    zabbix_server=server
                                                ).first()
                                                if monitoring_host and monitoring_host.ip_address:
                                                    host_instance = Host.objects.filter(
                                                        models.Q(private_ip=monitoring_host.ip_address) |
                                                        models.Q(public_ip=monitoring_host.ip_address)
                                                    ).first()
                                            except:
                                                pass

                                        # 方式3：如果还没找到，尝试模糊匹配hostname
                                        if not host_instance:
                                            host_instance = Host.objects.filter(
                                                hostname__icontains=hostname.split('.')[0]  # 去掉域名部分
                                            ).first()

                                    except Exception as e:
                                        logger.warning(f"查找主机失败: {e}")
                                        pass

                                # 创建或更新告警记录
                                from django.utils import timezone
                                import datetime

                                # 处理事件时间
                                event_time = timezone.now()
                                if alert.get('clock'):
                                    try:
                                        event_time = datetime.datetime.fromtimestamp(int(alert['clock']), tz=timezone.utc)
                                    except:
                                        pass

                                alert_obj, created = MonitoringAlert.objects.get_or_create(
                                    zabbix_event_id=alert.get('eventid'),
                                    defaults={
                                        'host': host_instance,
                                        'title': alert.get('name', '未知告警'),
                                        'severity': self._map_severity(alert.get('severity', '0')),
                                        'status': 'active' if alert.get('r_eventid') == '0' else 'resolved',
                                        'description': alert.get('name', ''),
                                        'zabbix_server': server,
                                        'zabbix_trigger_id': alert.get('objectid', ''),
                                        'event_time': event_time,
                                        'raw_data': alert
                                    }
                                )

                                if created:
                                    synced_alerts.append(alert_obj)

                            except Exception as e:
                                logger.warning(f"同步告警到数据库失败: {e}")

                        # 推送新告警到SSE
                        for alert in new_alerts:
                            self._push_alert(alert, server)

                        # 检查并同步已解决的告警
                        self._sync_resolved_alerts(server, alerts)

                        if new_alerts:
                            logger.info(f"发现 {len(new_alerts)} 个新告警来自 {server.name}")
                        if synced_alerts:
                            logger.info(f"同步 {len(synced_alerts)} 个告警到数据库")

                except Exception as e:
                    logger.error(f"检查Zabbix服务器 {server.name} 告警失败: {e}")

        except Exception as e:
            logger.error(f"检查新告警失败: {e}")

    def _push_alert(self, alert, zabbix_server):
        """推送告警到前端"""
        try:
            from .sse_manager import sse_manager

            # 获取主机信息
            hostname = "未知主机"
            host_ip = ""
            if alert.get('hosts') and len(alert['hosts']) > 0:
                hostname = alert['hosts'][0].get('name', alert['hosts'][0].get('host', '未知主机'))

            # 构造告警数据
            alert_data = {
                'id': f"zabbix_{alert.get('eventid', alert.get('problemid'))}",
                'title': alert.get('name', '未知告警'),
                'hostname': hostname,
                'severity': self._map_severity(alert.get('severity', '0')),
                'status': 'active',
                'event_time': alert.get('clock', ''),
                'zabbix_server': zabbix_server.name,
                'description': alert.get('name', ''),
                'host_ip': host_ip,
                'source': 'zabbix_monitor'
            }

            # 广播到所有SSE连接
            sse_manager.broadcast_to_all('new_alert', alert_data)
            logger.info(f"SSE推送新告警: {alert_data['title']} - {hostname}")

            # 发送邮件通知
            try:
                self._send_alert_notifications(alert_data, zabbix_server)
            except Exception as e:
                logger.error(f"发送告警邮件通知失败: {e}")

        except Exception as e:
            logger.error(f"推送告警失败: {e}")

    def _send_alert_notifications(self, alert_data, zabbix_server):
        """发送告警通知"""
        try:
            from .models import AlertRule, EmailConfig
            from .utils.notification_service import NotificationService

            # 检查是否有匹配的告警规则
            matching_rules = AlertRule.objects.filter(
                zabbix_server=zabbix_server,
                is_active=True,
                enable_notification=True
            )

            # 根据严重程度过滤规则 - 使用更宽松的匹配
            severity_mapping = {
                'disaster': 'critical',
                'high': 'high',
                'average': 'high',  # 将average映射为high，确保能匹配到规则
                'warning': 'high',  # 将warning也映射为high
                'information': 'medium',
                'not_classified': 'medium'
            }

            alert_severity = severity_mapping.get(alert_data.get('severity', 'high'), 'high')
            logger.info(f"告警严重程度映射: {alert_data.get('severity')} -> {alert_severity}")

            # 先尝试精确匹配严重程度
            severity_matched_rules = matching_rules.filter(severity=alert_severity)

            # 如果没有精确匹配，则使用所有启用的规则
            if not severity_matched_rules.exists():
                logger.info(f"没有找到严重程度为 {alert_severity} 的规则，使用所有启用的规则")
                matching_rules = matching_rules
            else:
                matching_rules = severity_matched_rules

            if not matching_rules.exists():
                logger.info(f"没有匹配的告警规则，跳过邮件通知")
                return

            # 获取默认邮件配置（用于备用）
            email_config = EmailConfig.objects.filter(is_default=True, is_active=True).first()

            # 发送通知 - 使用通知渠道系统
            for rule in matching_rules:
                # 遍历规则的所有通知渠道
                for channel in rule.notification_channels.filter(is_active=True):
                    if channel.channel_type == 'email':
                        # 邮件通知
                        recipients = channel.config.get('recipients', [])
                        if recipients:
                            subject = f"[{alert_data['severity'].upper()}] {alert_data['title']}"
                            content = f"""
告警详情：
- 标题：{alert_data['title']}
- 主机：{alert_data['hostname']}
- 严重程度：{alert_data['severity']}
- 时间：{alert_data['event_time']}
- Zabbix服务器：{alert_data['zabbix_server']}
- 描述：{alert_data['description']}

请及时处理此告警。
                            """.strip()

                            try:
                                # 添加邮件发送间隔，避免频率限制
                                import time
                                time.sleep(0.5)  # 500ms间隔

                                # 检查通知渠道是否有SMTP配置，如果没有则使用默认邮件配置
                                channel_config = channel.config
                                if channel_config.get('smtp_server'):
                                    # 使用通知渠道的SMTP配置
                                    self._send_email_with_channel_config(
                                        recipients=recipients,
                                        subject=subject,
                                        content=content,
                                        channel_config=channel_config
                                    )
                                else:
                                    # 使用默认邮件配置
                                    self._send_simple_email(
                                        recipients=recipients,
                                        subject=subject,
                                        content=content,
                                        email_config=email_config
                                    )
                                logger.info(f"告警邮件通知发送成功: {recipients}")
                            except Exception as e:
                                logger.error(f"告警邮件通知发送失败: {recipients}, 错误: {e}")

                    elif channel.channel_type in ['wechat', 'dingtalk']:
                        # 微信/钉钉通知
                        webhook_url = channel.config.get('webhook_url')
                        if webhook_url:
                            message = f"🚨 告警通知\n标题：{alert_data['title']}\n主机：{alert_data['hostname']}\n严重程度：{alert_data['severity']}\n时间：{alert_data['event_time']}"

                            try:
                                self._send_webhook_notification(webhook_url, message, channel.channel_type)
                                logger.info(f"告警{channel.channel_type}通知发送成功")
                            except Exception as e:
                                logger.error(f"告警{channel.channel_type}通知发送失败: {e}")

        except Exception as e:
            logger.error(f"发送告警通知失败: {e}")

    def _send_simple_email(self, recipients, subject, content, email_config):
        """发送HTML格式邮件通知"""
        try:
            import smtplib
            from email.mime.text import MIMEText
            from email.mime.multipart import MIMEMultipart

            if not email_config:
                logger.warning("没有找到邮件配置，跳过邮件发送")
                return

            # 生成HTML内容
            html_content = self._generate_alert_html(content, subject)

            # 连接SMTP服务器
            if email_config.use_ssl:
                server = smtplib.SMTP_SSL(email_config.smtp_server, email_config.smtp_port)
            else:
                server = smtplib.SMTP(email_config.smtp_server, email_config.smtp_port)
                if email_config.use_tls:
                    server.starttls()

            # 登录
            server.login(email_config.username, email_config.password)

            # 发送给每个收件人
            for recipient in recipients:
                # 创建邮件消息
                msg = MIMEMultipart('alternative')
                msg['From'] = email_config.from_email
                msg['To'] = recipient
                msg['Subject'] = subject

                # 添加纯文本和HTML版本
                text_part = MIMEText(content, 'plain', 'utf-8')
                html_part = MIMEText(html_content, 'html', 'utf-8')

                msg.attach(text_part)
                msg.attach(html_part)

                server.send_message(msg)
                logger.info(f"邮件发送成功: {recipient}")

            server.quit()

        except Exception as e:
            logger.error(f"HTML邮件发送失败: {e}")
            raise

    def _generate_alert_html(self, content, subject):
        """生成告警邮件的HTML内容 - 对标SSE通知渠道测试样式"""
        from django.utils import timezone

        # 解析内容获取告警信息
        lines = content.split('\n')
        alert_info = {}
        for line in lines:
            if '：' in line:
                key, value = line.split('：', 1)
                key = key.strip('- ')
                alert_info[key] = value.strip()

        # 根据严重程度设置颜色
        severity = alert_info.get('严重程度', 'unknown').lower()
        severity_colors = {
            'disaster': '#dc2626',
            'high': '#ea580c',
            'average': '#d97706',
            'warning': '#ca8a04',
            'information': '#2563eb',
            'not_classified': '#6b7280'
        }
        severity_color = severity_colors.get(severity, '#6b7280')

        html_template = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            margin: 0;
            padding: 20px;
        }}
        .container {{
            max-width: 600px;
            margin: 0 auto;
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            overflow: hidden;
            backdrop-filter: blur(10px);
        }}
        .header {{
            background: linear-gradient(135deg, {severity_color} 0%, {severity_color}dd 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }}
        .header h1 {{
            margin: 0;
            font-size: 28px;
            font-weight: 600;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
        }}
        .icon {{
            font-size: 48px;
            margin-bottom: 10px;
            display: block;
        }}
        .content {{
            padding: 30px;
        }}
        .alert-badge {{
            background: linear-gradient(135deg, {severity_color}, {severity_color}dd);
            color: white;
            padding: 12px 24px;
            border-radius: 25px;
            display: inline-block;
            font-weight: 600;
            margin-bottom: 20px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
        }}
        .config-grid {{
            background: #f8fafc;
            border-radius: 10px;
            padding: 20px;
            margin: 20px 0;
        }}
        .config-item {{
            display: flex;
            justify-content: space-between;
            padding: 8px 0;
            border-bottom: 1px solid #e2e8f0;
        }}
        .config-item:last-child {{
            border-bottom: none;
        }}
        .config-label {{
            font-weight: 600;
            color: #475569;
        }}
        .config-value {{
            color: #1e293b;
            font-family: 'Courier New', monospace;
        }}
        .footer {{
            background: #f1f5f9;
            padding: 20px;
            text-align: center;
            color: #64748b;
            font-size: 14px;
        }}
        .timestamp {{
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            padding: 10px 20px;
            border-radius: 25px;
            display: inline-block;
            margin-top: 20px;
            font-weight: 500;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <div class="icon">🚨</div>
            <h1>DevOps监控系统</h1>
            <p style="margin: 10px 0 0 0; opacity: 0.9;">系统告警通知</p>
        </div>

        <div class="content">
            <div class="alert-badge">
                🔥 {severity.upper()} 告警
            </div>

            <p style="font-size: 16px; line-height: 1.6; color: #334155;">
                <strong>{alert_info.get('标题', '未知告警')}</strong>
            </p>

            <div class="config-grid">
                <div class="config-item">
                    <span class="config-label">主机名称:</span>
                    <span class="config-value">{alert_info.get('主机', '未知主机')}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">严重程度:</span>
                    <span class="config-value" style="color: {severity_color}; font-weight: bold;">{alert_info.get('严重程度', '未知')}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">告警时间:</span>
                    <span class="config-value">{alert_info.get('时间', '未知时间')}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">Zabbix服务器:</span>
                    <span class="config-value">{alert_info.get('Zabbix服务器', '未知服务器')}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">告警描述:</span>
                    <span class="config-value">{alert_info.get('描述', '无描述信息')}</span>
                </div>
            </div>

            <p style="font-size: 14px; color: #64748b; line-height: 1.6;">
                💡 <strong>提示:</strong> 请及时处理告警，确保系统稳定运行。如有疑问，请联系系统管理员。
            </p>

            <div class="timestamp">
                🕒 发送时间: {timezone.now().strftime('%Y-%m-%d %H:%M:%S')}
            </div>
        </div>

        <div class="footer">
            <p>此邮件由 DevOps 监控系统自动发送，请勿回复。</p>
            <p style="margin: 5px 0 0 0;">如有问题，请联系系统管理员。</p>
        </div>
    </div>
</body>
</html>
        """.strip()

        return html_template

    def _send_email_with_channel_config(self, recipients, subject, content, channel_config):
        """使用通知渠道配置发送邮件"""
        try:
            import smtplib
            from email.mime.text import MIMEText
            from email.mime.multipart import MIMEMultipart

            # 从通知渠道配置获取SMTP信息
            smtp_server = channel_config.get('smtp_server')
            smtp_port = channel_config.get('smtp_port', 587)
            username = channel_config.get('username')
            password = channel_config.get('password')
            from_email = channel_config.get('from_email')
            use_ssl = channel_config.get('use_ssl', False)
            use_tls = channel_config.get('use_tls', True)

            if not all([smtp_server, username, password, from_email]):
                raise ValueError("通知渠道SMTP配置不完整")

            # 生成HTML内容
            html_content = self._generate_alert_html(content, subject)

            # 连接SMTP服务器
            if use_ssl:
                server = smtplib.SMTP_SSL(smtp_server, smtp_port)
            else:
                server = smtplib.SMTP(smtp_server, smtp_port)
                if use_tls:
                    server.starttls()

            # 登录
            server.login(username, password)

            # 发送给每个收件人
            for recipient in recipients:
                # 创建邮件消息
                msg = MIMEMultipart('alternative')
                msg['From'] = from_email
                msg['To'] = recipient
                msg['Subject'] = subject

                # 添加纯文本和HTML版本
                text_part = MIMEText(content, 'plain', 'utf-8')
                html_part = MIMEText(html_content, 'html', 'utf-8')

                msg.attach(text_part)
                msg.attach(html_part)

                server.send_message(msg)
                logger.info(f"通知渠道邮件发送成功: {recipient}")

            server.quit()

        except Exception as e:
            logger.error(f"通知渠道邮件发送失败: {e}")
            raise

    def _send_webhook_notification(self, webhook_url, message, channel_type):
        """发送Webhook通知"""
        try:
            import requests

            if channel_type == 'dingtalk':
                payload = {
                    "msgtype": "text",
                    "text": {
                        "content": message
                    }
                }
            elif channel_type == 'wechat':
                payload = {
                    "msgtype": "text",
                    "text": {
                        "content": message
                    }
                }
            else:
                payload = {"message": message}

            response = requests.post(webhook_url, json=payload, timeout=10)
            response.raise_for_status()

            logger.info(f"{channel_type}通知发送成功")

        except Exception as e:
            logger.error(f"{channel_type}通知发送失败: {e}")
            raise

    def _sync_resolved_alerts(self, zabbix_server, current_alerts):
        """同步已解决的告警状态"""
        try:
            from .models import MonitoringAlert
            from django.utils import timezone

            # 获取当前活跃告警的事件ID列表
            current_event_ids = set()
            for alert in current_alerts:
                if alert.get('r_eventid') == '0':  # 活跃告警
                    current_event_ids.add(alert.get('eventid'))

            # 查找数据库中该Zabbix服务器的活跃告警
            active_alerts = MonitoringAlert.objects.filter(
                zabbix_server=zabbix_server,
                status='active'
            )

            resolved_count = 0
            for db_alert in active_alerts:
                # 如果数据库中的告警不在当前活跃告警列表中，说明已被解决
                if db_alert.zabbix_event_id not in current_event_ids:
                    db_alert.status = 'resolved'
                    db_alert.resolved_time = timezone.now()
                    db_alert.save()
                    resolved_count += 1

                    logger.info(f"告警已解决: {db_alert.title} - {db_alert.host.hostname if db_alert.host else '未知主机'}")

                    # 发送告警恢复通知
                    try:
                        self._send_recovery_notifications(db_alert)
                    except Exception as e:
                        logger.error(f"发送告警恢复通知失败: {e}")

            if resolved_count > 0:
                logger.info(f"同步解决了 {resolved_count} 个告警状态")

        except Exception as e:
            logger.error(f"同步已解决告警失败: {e}")

    def _send_recovery_notifications(self, alert):
        """发送告警恢复通知"""
        try:
            from .models import NotificationChannel
            from .utils.notification_service import NotificationService

            # 获取活跃的邮件通知渠道
            email_channels = NotificationChannel.objects.filter(
                is_active=True,
                channel_type='email'
            )

            if not email_channels.exists():
                logger.info("没有找到活跃的邮件通知渠道，跳过恢复通知")
                return

            # 生成恢复通知内容
            subject = f"✅ 告警已恢复 - {alert.title}"

            # 生成告警恢复的HTML邮件内容（绿色主题）
            html_content = self._generate_recovery_html(alert, subject)
            text_content = self._generate_recovery_text(alert)

            # 发送到所有邮件通知渠道
            for channel in email_channels:
                try:
                    self._send_recovery_email_with_channel(channel, subject, html_content, text_content)
                    logger.info(f"告警恢复通知发送成功: {channel.name}")
                except Exception as e:
                    logger.error(f"告警恢复通知发送失败 - 渠道:{channel.name}: {e}")

        except Exception as e:
            logger.error(f"发送告警恢复通知失败: {e}")

    def _map_severity(self, zabbix_severity):
        """映射Zabbix严重级别"""
        severity_map = {
            '0': 'information',
            '1': 'information',
            '2': 'warning',
            '3': 'average',
            '4': 'high',
            '5': 'disaster'
        }
        return severity_map.get(str(zabbix_severity), 'information')

    def _generate_recovery_html(self, alert, subject):
        """生成告警恢复的HTML邮件内容 - 绿色主题"""
        from django.utils import timezone

        html_template = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #a4f4ba 0%, #22c55e 100%);
            margin: 0;
            padding: 20px;
        }}
        .container {{
            max-width: 600px;
            margin: 0 auto;
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            overflow: hidden;
            backdrop-filter: blur(10px);
        }}
        .header {{
            background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }}
        .header h1 {{
            margin: 0;
            font-size: 28px;
            font-weight: 600;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
        }}
        .icon {{
            font-size: 48px;
            margin-bottom: 10px;
            display: block;
        }}
        .content {{
            padding: 30px;
        }}
        .alert-badge {{
            background: linear-gradient(135deg, #22c55e, #16a34a);
            color: white;
            padding: 12px 24px;
            border-radius: 25px;
            display: inline-block;
            font-weight: 600;
            margin-bottom: 20px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
        }}
        .config-grid {{
            background: #f0fdf4;
            border-radius: 10px;
            padding: 20px;
            margin: 20px 0;
            border: 1px solid #bbf7d0;
        }}
        .config-item {{
            display: flex;
            justify-content: space-between;
            padding: 8px 0;
            border-bottom: 1px solid #dcfce7;
        }}
        .config-item:last-child {{
            border-bottom: none;
        }}
        .config-label {{
            font-weight: 600;
            color: #166534;
        }}
        .config-value {{
            color: #15803d;
            font-family: 'Courier New', monospace;
        }}
        .footer {{
            background: #f0fdf4;
            padding: 20px;
            text-align: center;
            color: #166534;
            font-size: 14px;
        }}
        .timestamp {{
            background: linear-gradient(135deg, #22c55e, #16a34a);
            color: white;
            padding: 10px 20px;
            border-radius: 25px;
            display: inline-block;
            margin-top: 20px;
            font-weight: 500;
        }}
        .success-message {{
            background: #dcfce7;
            border: 1px solid #bbf7d0;
            border-radius: 8px;
            padding: 15px;
            margin: 20px 0;
            color: #166534;
            font-weight: 500;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <div class="icon">✅</div>
            <h1>DevOps监控系统</h1>
            <p style="margin: 10px 0 0 0; opacity: 0.9;">告警恢复通知</p>
        </div>

        <div class="content">
            <div class="alert-badge">
                🎉 告警已恢复
            </div>

            <p style="font-size: 16px; line-height: 1.6; color: #334155;">
                <strong>{alert.title}</strong>
            </p>

            <div class="success-message">
                🎊 好消息！此告警已经自动恢复，系统运行正常。
            </div>

            <div class="config-grid">
                <div class="config-item">
                    <span class="config-label">告警标题:</span>
                    <span class="config-value">{alert.title}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">主机名称:</span>
                    <span class="config-value">{alert.host.hostname if alert.host else '未知主机'}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">严重程度:</span>
                    <span class="config-value" style="color: #22c55e; font-weight: bold;">{alert.get_severity_display()}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">告警时间:</span>
                    <span class="config-value">{alert.event_time.strftime('%Y-%m-%d %H:%M:%S') if alert.event_time else '未知时间'}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">恢复时间:</span>
                    <span class="config-value">{alert.resolved_time.strftime('%Y-%m-%d %H:%M:%S') if alert.resolved_time else timezone.now().strftime('%Y-%m-%d %H:%M:%S')}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">Zabbix服务器:</span>
                    <span class="config-value">{alert.zabbix_server.name if alert.zabbix_server else '未知服务器'}</span>
                </div>
                <div class="config-item">
                    <span class="config-label">告警描述:</span>
                    <span class="config-value">{alert.description or '无描述信息'}</span>
                </div>
            </div>

            <p style="font-size: 14px; color: #166534; line-height: 1.6;">
                💡 <strong>提示:</strong> 告警已自动恢复，无需人工干预。如有疑问，请联系系统管理员。
            </p>

            <div class="timestamp">
                🕒 通知时间: {timezone.now().strftime('%Y-%m-%d %H:%M:%S')}
            </div>
        </div>

        <div class="footer">
            <p>此邮件由 DevOps 监控系统自动发送，请勿回复。</p>
            <p style="margin: 5px 0 0 0;">如有问题，请联系系统管理员。</p>
        </div>
    </div>
</body>
</html>
        """.strip()

        return html_template

    def _generate_recovery_text(self, alert):
        """生成告警恢复的纯文本内容"""
        from django.utils import timezone

        text_content = f"""
✅ DevOps监控系统 - 告警恢复通知

🎉 告警已恢复: {alert.title}

告警详情:
- 告警标题: {alert.title}
- 主机名称: {alert.host.hostname if alert.host else '未知主机'}
- 严重程度: {alert.get_severity_display()}
- 告警时间: {alert.event_time.strftime('%Y-%m-%d %H:%M:%S') if alert.event_time else '未知时间'}
- 恢复时间: {alert.resolved_time.strftime('%Y-%m-%d %H:%M:%S') if alert.resolved_time else timezone.now().strftime('%Y-%m-%d %H:%M:%S')}
- Zabbix服务器: {alert.zabbix_server.name if alert.zabbix_server else '未知服务器'}
- 告警描述: {alert.description or '无描述信息'}

💡 提示: 告警已自动恢复，无需人工干预。如有疑问，请联系系统管理员。

🕒 通知时间: {timezone.now().strftime('%Y-%m-%d %H:%M:%S')}

此邮件由 DevOps 监控系统自动发送，请勿回复。
        """.strip()

        return text_content

    def _send_recovery_email_with_channel(self, channel, subject, html_content, text_content):
        """使用指定通知渠道发送恢复邮件"""
        import smtplib
        from email.mime.text import MIMEText
        from email.mime.multipart import MIMEMultipart

        config = channel.config

        # 优先使用通知渠道的直接配置
        smtp_server = config.get('smtp_server')
        smtp_port = config.get('smtp_port', 587)
        username = config.get('username')
        password = config.get('password')
        from_email = config.get('from_email')
        use_ssl = config.get('use_ssl', False)
        use_tls = config.get('use_tls', True) if not use_ssl else False

        # 如果通知渠道没有完整的直接配置，再尝试使用邮件配置ID
        if not all([smtp_server, username, password, from_email]):
            email_config_id = config.get('email_config_id')
            if email_config_id:
                from .models import EmailConfig
                try:
                    email_config = EmailConfig.objects.get(id=email_config_id, is_active=True)
                    smtp_server = email_config.smtp_server
                    smtp_port = email_config.smtp_port
                    username = email_config.username
                    password = email_config.password
                    from_email = email_config.from_email
                    use_tls = email_config.use_tls
                    use_ssl = email_config.use_ssl
                except EmailConfig.DoesNotExist:
                    raise ValueError(f"邮件配置ID {email_config_id} 不存在，且通知渠道配置不完整")

        # 获取收件人列表
        recipients = config.get('recipients', [])
        if not recipients:
            recipients = [from_email]  # 如果没有收件人，发送给自己

        # 验证必要字段
        if not all([smtp_server, username, password, from_email]):
            raise ValueError("邮件配置不完整，请检查SMTP服务器、用户名、密码和发件人邮箱设置")

        # 发送邮件
        server = None
        try:
            # 建立连接
            if use_ssl:
                server = smtplib.SMTP_SSL(smtp_server, smtp_port)
            else:
                server = smtplib.SMTP(smtp_server, smtp_port)
                if use_tls:
                    server.starttls()

            # 登录
            server.login(username, password)

            # 发送邮件
            for recipient in recipients:
                msg = MIMEMultipart('alternative')
                msg['From'] = from_email
                msg['To'] = recipient
                msg['Subject'] = subject

                # 先添加纯文本版本，再添加HTML版本（HTML优先显示）
                msg.attach(MIMEText(text_content, 'plain', 'utf-8'))
                msg.attach(MIMEText(html_content, 'html', 'utf-8'))

                server.send_message(msg)

        except Exception as e:
            logger.error(f"恢复邮件发送失败: {e}")
            raise
        finally:
            if server:
                try:
                    server.quit()
                except Exception as e:
                    logger.warning(f"关闭SMTP连接时出错: {e}")


# 全局告警监控器实例
zabbix_alert_monitor = ZabbixAlertMonitor()

def start_zabbix_alert_monitoring():
    """启动Zabbix告警监控"""
    zabbix_alert_monitor.start_monitoring()

def stop_zabbix_alert_monitoring():
    """停止Zabbix告警监控"""
    zabbix_alert_monitor.stop_monitoring()
